﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data.Linq;
using System.Linq;
using System.Text;
using IntraVision.Web;
using IntraVision.Web.Filter;
using IntraVision.Web.Security;
using Model;
using LZMA;
using System.Data.Linq.SqlClient;

[Security]
public class PersonController : TableController<NotarialServiceDataContext, Person>
{
    bool create = false;
    bool isUnionMode = false;
    private int? companyId;

    public PersonController() {}

    protected override void EntityLoaded(NotarialServiceDataContext dc, Person entity)
    {
        //Добавляем скрипт для поддержки выпадающих списков с множественным выбором и автокомплита
        RegisterScript("jquery.multipleselect.js", "table.js", "jquery.autocomplete.js", "jquery.ui.packed.js");
        RegisterStylesheet("autocomplete/autocomplete.css");

        CheckIsExternal();
        CheckIsRegData();

        if (!string.IsNullOrEmpty(Request["opener"]))
            ViewData["opener"] = Request["opener"];

        if (entity.Id == 0) //create
            ViewData["queryParams"] = Request.Url.Query;

        if (!string.IsNullOrEmpty(Request["returntoopeneraftersave"]))
            ViewData["returnToOpenerAfterSave"] = true;

        ViewData["roles"] = (from r in dc.Roles select r).ToList();

        if (entity.PassportPhotoFileId.HasValue && entity.PassportPhotoFileId > 0)
            ViewData["photofile"] = entity.PhotoFile;

        if (entity.PassportDataFileId.HasValue && entity.PassportDataFileId > 0)
            ViewData["infofile"] = entity.InfoFile;

        string hashKey = string.Empty;
        if (isUnionMode)
            ViewData["possiblelist"] = PrepareUnionPossibleItems(dc, entity, true, ref hashKey);
    }

    protected override void BeforeSubmit(NotarialServiceDataContext dc, Person person)
    {
        create = (person.Id == 0);
        var cidStr = Request["unionpersonid"];
        //режим объединения
        if (!string.IsNullOrEmpty(cidStr))
        {
            int cid = 0;
            if (int.TryParse(cidStr, out cid) && cid > 0)
            {
                var srcPerson = dc.Persons.FirstOrDefault(c => c.Id == cid);
                if (!string.IsNullOrEmpty(Request["isunionorders"]))
                {
                    foreach (var o in srcPerson.OrderClientPersons)
                        o.PersonId = person.Id;
                    foreach (var o in srcPerson.OrderResponsiblePersons)
                        o.PersonId = person.Id;
                }
                if (!string.IsNullOrEmpty(Request["isunionpersons"]))
                {
                    foreach (var o in srcPerson.CompanyPersons.Where(cp => !person.CompanyPersons.Any(c => c.CompanyId == cp.CompanyId)))
                        person.CompanyPersons.Add(new CompanyPerson { Company = o.Company });
                    dc.CompanyPersons.DeleteAllOnSubmit(srcPerson.CompanyPersons);
                }
                srcPerson.IsArchive = true;
                if (!string.IsNullOrEmpty(Request["isdeletesrc"]))
                    dc.Persons.DeleteOnSubmit(srcPerson);
            }
        }
        //обычное сохранение
        else
        {
            if (!string.IsNullOrEmpty(Request["password"]))
                person.Password = RequestHelper.MD5Encode(Request["password"]);

            person.PhonePartsArray = new string[4] { Request["phone1"], Request["phone2"], Request["phone3"], Request["phone4"] };

            //Сохранить файлы в базу
            UploadFiles(person, (Session["user"] as User));
        }
    }

    protected override void AfterSubmit(NotarialServiceDataContext dc, Person entity)
    {
        Logger.WriteLog(dc, (create) ? LogOperationType.ClientCreate : LogOperationType.ClientChange, (Session["User"] as User).Id, null, null);
    }

    public void UnionList()
    {
        isUnionMode = true;
        _ActionKey = Action;
        LayoutPath = "~/views/layouts/page.haml";
        TemplatePath = "~/views/person/unionlist.haml";
        ViewData["hidecb"] = true;
        ProcessTable();
    }

    protected override IQueryable<Person> Paginate(IQueryable<Person> query)
    {
        if (isUnionMode)
            return query;
        return base.Paginate(query);
    }

    [AllowedRole("IsAdmin")]
    public override void List()
    {
        base.List();
    }

    public override void Create()
    {
        var pname = string.IsNullOrEmpty(Request["possiblename"]) ? "" : Request["possiblename"].Trim();
        if (!string.IsNullOrEmpty(pname))
        {       
            var list = new List<string>(pname.Split(' '));
            list.RemoveAll(a => string.IsNullOrEmpty(a.Trim()));
            if (list.Count > 0) 
                ViewData["lastname"] = list[0];
            if (list.Count > 1)
                ViewData["name"] = list[1];
            if (list.Count > 2)
                ViewData["patronymicname"] = String.Join(" ", list.ToArray(), 2, list.Count - 2);
        }
        base.Create();
    }

    protected override void CreateFilterConditions(NotarialServiceDataContext dc)
    {
        Filter = new Filter<Person>();
        bool isSelect = ViewData.ContainsKey("ActionKey") && ViewData["ActionKey"].ToString() == "select";

        Filter.Conditions.Add(new StringFilterCondition<Person>("LastName", "Фамилия"));
        Filter.Conditions.Add(new StringFilterCondition<Person>("Name", "Имя"));
        Filter.Conditions.Add(new StringFilterCondition<Person>("PatronymicName", "Отчество"));
        Filter.Conditions.Add(new StringFilterCondition<Person>("Email", "Email"));
        Filter.Conditions.Add(new UserRelationFilterCondition<Person>(
            "CompanyPersons",
            "PersonId",
            "Юридические лица",
            (from c in dc.Companies orderby c.Name select new { Id = c.Id, Name = c.Name }),
            -1,
            "",//"order.ivp/findclients", 
            "company.ivp/select?reset=true"));

        if (!isSelect)
        {
            Filter.Conditions.Add(new NumericFilterCondition<Person>("Id", "Номер"));
            Filter.Conditions.Add(new BoolFilterCondition<Person>("IsActivated", "Активирован"));
            Filter.Conditions.Add(new BoolFilterCondition<Person>("IsArchive", "Архивный"));
        }
    }

    protected override IQueryable ConvertQueryToResult(NotarialServiceDataContext dc, IQueryable<Person> query)
    {
        string hashKey = string.Empty;
        if (isUnionMode)
        {
            var list = query.ToList();
            return (from q in list
                    select new SimpleObject
                    {
                        Id = q.Id,
                        Name = ToHtml(PrepareUnionPossibleItems(list, q, false, ref hashKey), q),
                        HashKey = hashKey
                    }).Where(c => c.Name.IndexOf("<li>") != c.Name.LastIndexOf("<li>"))
                    .Distinct(new SimpleObjectNameComparer())
                    .AsQueryable();
        }
        return (from q in query
                select new
                {
                    Id = q.Id,
                    FIO = q.FIO,
                    Name = q.Name, 
                    LastName = q.LastName,
                    PatronymicName = q.PatronymicName,
                    Email = q.Email,
                    Phone = q.Phone,
                    RoleName = q.Role.Name,
                    IsArchive= q.IsArchive,
                    IsActivated = q.IsActivated,
                    TaskCount = q.Tasks.Count
                });
    }

    protected override IQueryable<Person> Search(IQueryable<Person> query)
    {
        //Добавим поиск по идентификатору заявки
        if (!string.IsNullOrEmpty(State["tb_search"]))
        {
            //поиск по заявителям
            int[] persons;
            using (var dc = new NotarialServiceDataContext())
            {
                string search =  State["tb_search"].Trim().ToLower();
                persons = (from p in dc.Persons.ToList<Person>().Where<Person>(p => p.FIO.ToLower().IndexOf(search) > -1) select p.Id).ToArray<int>();            
            }
            query = (base.Search(query).Union<Person>(query.Where(p => ((persons.Length > 0) && persons.Contains(p.Id))))).Distinct<Person>();
        }
        return query;
    }

    [AllowedRole("IsAdmin")]
    public void Select()
    {  
        ViewData["hidecb"] = ViewData["popup"] = true;
        RegisterScript("table.js", "jquery.multipleselect.js", "user/select.js");

        _ActionKey = Action;
        if (String.IsNullOrEmpty(Request["nolayout"]))
        {
            LayoutPath = "~/views/layouts/popup.haml";
            TemplatePath = "~/views/person/select.haml";
        }
        else TemplatePath = "~/views/_table/table.haml";

        ProcessTable();
    }

    [AllowedRole("IsAdmin")]
    public override void View(string entityid)
    {
        if (!string.IsNullOrEmpty(Request["popup"]) && Request["popup"] == "true")
        {
            LayoutPath = "~/views/layouts/popup.haml";
            TemplatePath = "~/views/person/form.haml";

            if (string.IsNullOrEmpty(Request["edit"]))
            {
                ViewData["popup"] = true;
                ViewData["readonly"] = string.IsNullOrEmpty(Request["edit"]);
            }
            else
                ViewData["edit"] = true;

            ViewData["isexternal"] = true;
        }   
        base.View(entityid);
    }

    public void RegData()
    {
        var person = Session["user"] as Person;
        if (person != null)
        {
            CheckIsRegData();
            View(person.Id.ToString());
        }
    }

    private void CheckIsRegData()
    {
        if (Session["user"] is Person)
            ViewData["regdata"] = true;
    }

    private void CheckIsExternal()
    {
        if (!string.IsNullOrEmpty(Request["isexternal"]) && Request["isexternal"].ToLower() == "true")
        {
            LayoutPath = "~/views/layouts/popup.haml";
            TemplatePath = "~/views/person/form.haml";
            if (string.IsNullOrEmpty(Request["edit"]))
            {
                ViewData["popup"] = true;
            }
            else
                ViewData["edit"] = true;

            ViewData["isexternal"] = true;
        }
    }

    protected override void ReturnAfterSave(string page)
    {
        Response.Redirect((Session["personmode"] as string) ?? "client.ivp/list");
    }

    /// <summary>
    /// Присоединить файлы к заявке
    /// </summary>
    private void UploadFiles(Person person, User user)
    {
        if (Request.Files.Count > 0)
        {
            for (int i = 0; i < Request.Files.Count; i++)
            {
                var file = Request.Files[i];
                var fileContent = RequestHelper.GetPostedFileContent(file);
                if (fileContent.Length == 0) continue;

                var df = new DataFile();
                df.Data = fileContent;
                df.Created = DateTime.Now;
                df.Name = System.IO.Path.GetFileName(file.FileName);

                if (Request.Files.AllKeys[i] == "infofile")
                    person.InfoFile = df;
                if (Request.Files.AllKeys[i] == "photofile")
                    person.PhotoFile = df;
            }
        }
    }

    public void RemoveFile(string fileid)
    {
        var user = Session["user"] as User;
        using (var dc = new NotarialServiceDataContext())
        {
            int fid;
            Int32.TryParse(fileid, out fid);

            var file = dc.DataFiles.Single(f => f.Id == fid);

            try
            {
                var p1 = file.Persons.FirstOrDefault();
                if (p1 != null) p1.InfoFile = null;

                var p2 = file.Persons1.FirstOrDefault();
                if (p2 != null) p2.PhotoFile = null;

                dc.DataFiles.DeleteOnSubmit(file);
                dc.SubmitChanges();
            }
            catch (Exception ex)
            {
                RenderJSON(new AJAXResult(ex));
                return;
            }
            RenderJSON(new AJAXResult { Id = fileid });
        }
    }

    public void ViewFile(string fileid)
    {
        using (var dc = new NotarialServiceDataContext())
        {
            int fid = 0;
            Int32.TryParse(fileid, out fid);

            var file = dc.DataFiles.Single(f => f.Id == fid);

            Response.ContentType = "application/octet-stream";
            Response.AppendHeader("Content-Disposition", "attachment;filename=\"" + file.Name + "\"");
            Response.HeaderEncoding = Encoding.GetEncoding("windows-1251");
            Response.ContentEncoding = Encoding.GetEncoding("windows-1251");
            byte[] bytes;
            try
            {
                bytes = Extractor.ExtractBytes(file.Data.ToArray());
            }
            catch
            {
                bytes = file.Data.ToArray();
            }
            Response.BinaryWrite(bytes);

            Response.Flush();
            Response.End();
        }
    }

    public void LoadCompanyPersons()
    {
        if (!string.IsNullOrEmpty(Request["companyid"]))
            companyId = Convert.ToInt32(Request["companyid"]);

        _ActionKey = Action;
        //ViewData["hidecb"] = true;

        TemplatePath = "~/views/person/personcompany.haml";
        LayoutPath = "none";

        ProcessTable();
    }

    protected override IQueryable<Person> CustomFilter(NotarialServiceDataContext dc, IQueryable<Person> query)
    {
        if (companyId.HasValue)
            return query.Where(q => q.CompanyPersons.Any(cp => cp.CompanyId == companyId.Value));
        if (isUnionMode)
        {
            var code = 0;
            var letter = "а";
            if (int.TryParse(Request["letter"], out code) && code > 0)            
                letter = Char.ConvertFromUtf32((int)code).ToLower();
            ViewData["code"] = Char.ConvertToUtf32(letter.ToUpper(),0);
            return query.Where(q => !q.IsArchive && q.LastName.Trim().ToLower().StartsWith(letter));
        }
        return base.CustomFilter(dc, query);
    }

    #region union

    [AllowedRole("IsAdmin")]
    public void Union(string entityid)
    {
        TemplatePath = "~/views/person/union.haml";
        isUnionMode = true;
        base.View(entityid);
    }

    [AllowedRole("IsAdmin")]
    public void LoadUnionSource(string entityid)
    {
        TemplatePath = "~/views/person/_unionsource.haml";
        ViewData["issourceperson"] = true;
        base.View(entityid);
    }

    protected IList<Person> PrepareUnionPossibleItems(IList<Person> persons, Person person, bool excludeSelf, ref string hashKey)
    {
        var result = new List<Person>();
        var name = !string.IsNullOrEmpty(person.LastName) ? person.LastName.Trim().ToLower() : string.Empty;
        if (!string.IsNullOrEmpty(name) && name.Length > 5)
        {
            var search = name.Trim().Substring(0, 5);
            result = persons.Where(c => (!excludeSelf || c.Id != person.Id) && c.LastName.Trim().ToLower().StartsWith(search)).ToList();
        }
        if (result != null && result.Count > 0)
            hashKey = string.Join(",", result.OrderBy(r => r.Id).Select(r => r.Id.ToString()).ToArray());

        return result;
    }

    protected IList<Person> PrepareUnionPossibleItems(NotarialServiceDataContext dc, Person person, bool excludeSelf, ref string hashKey)
    {
        var result = new List<Person>();
        var name = !string.IsNullOrEmpty(person.LastName) ? person.LastName.Trim().ToLower() : string.Empty;
        if (!string.IsNullOrEmpty(name))
        {
            var search = string.Format("{0}%", name.Substring(0, (name.Length < 5) ? name.Length : 5).Trim());
            result = dc.Persons.Where(c => !c.IsArchive && (!excludeSelf || c.Id != person.Id) && SqlMethods.Like(c.LastName.ToLower().Trim(), search)).ToList();
        }
        if (result != null && result.Count > 0)
            hashKey = string.Join(",", result.OrderBy(r => r.Id).Select(r => r.Id.ToString()).ToArray());
        return result;
    }

    protected string ToHtml(IList<Person> list, Person first)
    {
        var result = new StringBuilder();
        result.Append("<ul>");
        result.Append(string.Format("<li>{0}</li>", first.ToUnionLink()));
        foreach (var c in list.Where(l => l.Id != first.Id))
            result.Append(string.Format("<li>{0}</li>", c.ToUnionLink()));
        result.Append("</ul>");
        return result.ToString();
    }

    #endregion
}
